package com.ffcs.crmd.tsp.server.util;

import java.util.Calendar;
import java.util.TimeZone;
import java.util.UUID;

import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.quartz.CronScheduleBuilder;
import org.quartz.CronTrigger;
import org.quartz.Job;
import org.quartz.JobBuilder;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.SimpleScheduleBuilder;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.quartz.TriggerBuilder;

import com.ffcs.crmd.tsp.api.dto.client.TspJob;
import com.ffcs.crmd.tsp.api.dto.client.TspJobDetail;
import com.ffcs.crmd.tsp.api.dto.enu.JobDetailState;
import com.ffcs.crmd.tsp.api.dto.enu.JobMisfireInstruction;
import com.ffcs.crmd.tsp.api.dto.enu.JobRecover;
import com.ffcs.crmd.tsp.api.dto.enu.JobRepeatType;
import com.ffcs.crmd.tsp.api.dto.enu.JobTimeoutPolicy;
import com.ffcs.crmd.tsp.api.dto.enu.JobType;
import com.ffcs.crmd.tsp.api.dto.task.TspJobDataMap;
import com.ffcs.crmd.tsp.api.dto.task.TspJobInstance;
import com.ffcs.crmd.tsp.common.constant.TspAppConstant;
import com.ffcs.crmd.tsp.common.exception.TspException;
import com.ffcs.crmd.tsp.core.util.BeanUtils;
import com.ffcs.crmd.tsp.core.util.MixAll;
import com.ffcs.crmd.tsp.server.jdbc.entity.JobDetailParam;

/**
 * 
 * 功能说明:任务转换工具类
 *
 * @author FFCS-ZHONGFUHUA
 * 
 * @since 1.0.0-SNAPSHOT
 *
 */
public class JobDetailHelper {
    
    protected JobDetailHelper() {
        
    }
    
    /**
     * 
     * 功能说明:获取标识
     * 
     * @author ZHONGFUHUA
     *
     * @Date 2016年4月10日
     *
     */
    public static String getId() {
        UUID uuid = UUID.randomUUID();
        return uuid.toString();
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param tspJobVo
     * @param job
     * @return
     * @throws Exception 
     */
    public static com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail convert2JobDetailEntity(TspJobDetail tspJobDetail,
        com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail jobDetail) throws Exception {
        if(CollectionUtils.isNotEmpty(tspJobDetail.getParams())){
            jobDetail.setParams(BeanUtils.copyList(tspJobDetail.getParams(), JobDetailParam.class));
        }
        
        /*switch (tspJobDetail.getJobDetailState()) {
            case PAUSED:
                jobDetail.setRunning((short) 0);
                break;
            case NORMAL:
                jobDetail.setRunning((short) 1);
                break;
            case BLOCKED:
                jobDetail.setRunning((short) 2);
                break;
            case COMPLETE:
                jobDetail.setRunning((short) 3);
                break;
            case ERROR:
                jobDetail.setRunning((short) 4);
                break;
            default:
                jobDetail.setRunning((short) 5);
                break;
        }*/
        return jobDetail;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param tspJobVo
     * @param job
     * @return
     */
    public static TspJobDetail convert2JobDetailVO(TspJobDetail tspJobDetailVo, com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail jobDetail) {
        switch (jobDetail.getRunning()) {
            case 0:
                tspJobDetailVo.setJobDetailState(JobDetailState.PAUSED);
                break;
            case 1:
                tspJobDetailVo.setJobDetailState(JobDetailState.NORMAL);
                break;
            case 2:
                tspJobDetailVo.setJobDetailState(JobDetailState.BLOCKED);
                break;
            case 3:
                tspJobDetailVo.setJobDetailState(JobDetailState.COMPLETE);
                break;
            case 4:
                tspJobDetailVo.setJobDetailState(JobDetailState.ERROR);
                break;
            default:
                tspJobDetailVo.setJobDetailState(JobDetailState.NONE);
                break;
        }
        return tspJobDetailVo;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param tspJobVo
     * @param job
     * @return
     */
    public static com.ffcs.crmd.tsp.server.jdbc.entity.Job convert2JobEntity(TspJob tspJobVo, com.ffcs.crmd.tsp.server.jdbc.entity.Job job) {
        switch (tspJobVo.getJobType()) {
            case NORMAL:
                job.setType((short) 0);
                break;
            case STATEFUL:
                job.setType((short) 1);
                break;
        }
        
        switch (tspJobVo.getJobRecover()) {
            case FALSE:
                job.setShouldRecover((short) 0);
                break;
            case TRUE:
                job.setShouldRecover((short) 1);
                break;
        }
        
        switch (tspJobVo.getJobRepeatType()) {
            case NORMAL:
                job.setRepeatType((short) 0);
                job.setCronExpression(null);
                break;
            case CRON:
                job.setRepeatType((short) 1);
                job.setRepeatCount(null);
                job.setRepeatInterval(null);
                break;
        }
        
        switch (tspJobVo.getJobTimeoutPolicy()) {
            case IGNORE:
                job.setTimeoutPolicy((short) 0);
                break;
            case TRANSFER:
                job.setTimeoutPolicy((short) 1);
                break;
            case FINISH:
                job.setTimeoutPolicy((short) 2);
                break;
        }
        
        switch (tspJobVo.getJobMisfireInstruction()) {
            case IGNORE_MISFIRE_POLICY:
                job.setMisfireInstruction((short) -1);
                break;
            case SMART_POLICY:
                job.setMisfireInstruction((short) 0);
                break;
            case FIRE_NOW:
                job.setMisfireInstruction((short) 1);
                break;
            case RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT:
                job.setMisfireInstruction((short) 2);
                break;
            case RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT:
                job.setMisfireInstruction((short) 3);
                break;
            case RESCHEDULE_NEXT_WITH_REMAINING_COUNT:
                job.setMisfireInstruction((short) 4);
                break;
            case RESCHEDULE_NEXT_WITH_EXISTING_COUNT:
                job.setMisfireInstruction((short) 5);
                break;
            case FIRE_AND_PROCEED:
                job.setMisfireInstruction((short) 1);
                break;
            case DO_NOTING:
                job.setMisfireInstruction((short) 2);
                break;
        }
        return job;
    }
    
    /**
     * 
     * 功能说明:
     * 
     * @param tspJobVo
     * @param job
     * @return
     */
    public static TspJob convert2JobVO(TspJob tspJobVo, com.ffcs.crmd.tsp.server.jdbc.entity.Job job) {
        switch (job.getType()) {
            case 0:
                tspJobVo.setJobType(JobType.NORMAL);
                break;
            case 1:
                tspJobVo.setJobType(JobType.STATEFUL);
                break;
        }
        
        switch (job.getShouldRecover()) {
            case 0:
                tspJobVo.setJobRecover(JobRecover.FALSE);
                break;
            case 1:
                tspJobVo.setJobRecover(JobRecover.TRUE);
                break;
        }
        
        switch (job.getRepeatType()) {
            case 0:
                tspJobVo.setJobRepeatType(JobRepeatType.NORMAL);
                break;
            case 1:
                tspJobVo.setJobRepeatType(JobRepeatType.CRON);
                break;
        }
        
        switch (job.getTimeoutPolicy()) {
            case 0:
                tspJobVo.setJobTimeoutPolicy(JobTimeoutPolicy.IGNORE);
                break;
            case 1:
                tspJobVo.setJobTimeoutPolicy(JobTimeoutPolicy.TRANSFER);
                break;
            case 2:
                tspJobVo.setJobTimeoutPolicy(JobTimeoutPolicy.FINISH);
                break;
        }
        
        switch (job.getMisfireInstruction()) {
            case -1:
                tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.IGNORE_MISFIRE_POLICY);
                break;
            case 0:
                tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.SMART_POLICY);
                break;
            case 1:
                if (job.getRepeatType() == 0) {
                    tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.FIRE_NOW);
                } else {
                    tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.FIRE_AND_PROCEED);
                }
                break;
            case 2:
                if (job.getRepeatType() == 0) {
                    tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.RESCHEDULE_NOW_WITH_EXISTING_REPEAT_COUNT);
                } else {
                    tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.DO_NOTING);
                }
                break;
            case 3:
                tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.RESCHEDULE_NOW_WITH_REMAINING_REPEAT_COUNT);
                break;
            case 4:
                tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
                break;
            case 5:
                tspJobVo.setJobMisfireInstruction(JobMisfireInstruction.RESCHEDULE_NEXT_WITH_EXISTING_COUNT);
                break;
        }
        return tspJobVo;
    }
    
    /**
     * 
     * 功能说明:tsp任务转换成quartz任务
     * 
     * @param jobDetail
     * @param job
     * @return
     * @throws TspException
     */
    @SuppressWarnings("unchecked")
    public static JobDetail convert2JobDetail(com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail jobDetail, com.ffcs.crmd.tsp.server.jdbc.entity.Job job)
        throws TspException {
        try {
            if (StringUtils.isBlank(jobDetail.getName()) && StringUtils.isBlank(job.getName())) {
                throw new TspException("job detail name and job name can't be null");
            }
            
            if (StringUtils.isBlank(job.getJobClass())) {
                throw new TspException("job detail class can't be null");
            }
            
            Class<? extends Job> jobClass = null;
            switch (job.getType()) {
                case 0:
                    jobClass = (Class<? extends Job>) Class.forName(MixAll.TSP_JOB);
                    break;
                case 1:
                    jobClass = (Class<? extends Job>) Class.forName(MixAll.TSP_STATEFUL_JOB);
                    break;
                case 2:
                    jobClass = (Class<? extends Job>) Class.forName(MixAll.TSP_INTERRUPT_JOB);
                    break;
            }
            
            JobBuilder jobBuilder = JobBuilder.newJob(jobClass);
            jobBuilder.withIdentity(jobDetail.getName(), job.getName());
            jobBuilder.usingJobData(MixAll.TSP_JOB_CLASS, job.getJobClass());
            jobBuilder.withDescription(job.getDescription());
            
            if (CollectionUtils.isNotEmpty(jobDetail.getParams())) {
                for (JobDetailParam jobDetailParam : jobDetail.getParams()) {
                    jobBuilder.usingJobData(jobDetailParam.getMkey(), jobDetailParam.getMvalue());
                }
            }
            
            if (job.getShouldRecover() == 1) {
                jobBuilder.requestRecovery();
            }
            return jobBuilder.build();
        } catch (ClassNotFoundException e) {
            throw new TspException(e);
        }
    }
    
    /**
     * 
     * 功能说明:tsp子任务转换成quartz简单触发器
     * 
     * @param jobDetail
     * @param job
     * @return
     * @throws TspException
     */
    public static SimpleTrigger convert2SimpleTrigger(com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail jobDetail,
        com.ffcs.crmd.tsp.server.jdbc.entity.Job job, boolean update) throws TspException {
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
        if (StringUtils.isBlank(jobDetail.getName()) && StringUtils.isBlank(job.getName())) {
            throw new TspException("job detail name and job name can't be null");
        }
        
        if (jobDetail.getStartTime() == null) {
            if(update){
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.SECOND, 60);
                triggerBuilder.startAt(calendar.getTime());
            }else{
                triggerBuilder.startNow();
            }
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND, 60);
            if(jobDetail.getStartTime().getTime() > calendar.getTime().getTime()){
                triggerBuilder.startAt(jobDetail.getStartTime());
            }else{
                triggerBuilder.startAt(calendar.getTime());
            }
        }
        
        if (jobDetail.getEndTime() != null) {
            triggerBuilder.endAt(jobDetail.getEndTime());
        }
        
        try {
            SimpleScheduleBuilder simpleScheduleBuilder = SimpleScheduleBuilder.simpleSchedule();
            simpleScheduleBuilder.withIntervalInMilliseconds(job.getRepeatInterval().longValue());
            simpleScheduleBuilder.withRepeatCount(job.getRepeatCount().intValue());
            switch (job.getMisfireInstruction()) {
                case -1:
                    simpleScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
                    break;
                case 0:
                    simpleScheduleBuilder.withMisfireHandlingInstructionFireNow();
                    break;
                case 2:
                    simpleScheduleBuilder.withMisfireHandlingInstructionNowWithExistingCount();
                    break;
                case 3:
                    simpleScheduleBuilder.withMisfireHandlingInstructionNowWithRemainingCount();
                    break;
                case 4:
                    simpleScheduleBuilder.withMisfireHandlingInstructionNextWithRemainingCount();
                    break;
                case 5:
                    simpleScheduleBuilder.withMisfireHandlingInstructionNextWithExistingCount();
                    break;
            }
            triggerBuilder.withIdentity(MixAll.TSP_TRIGGER_PREFIX + jobDetail.getName(), MixAll.TSP_TRIGGER_PREFIX + job.getName());
            triggerBuilder.withSchedule(simpleScheduleBuilder);
        } catch (Exception e) {
            throw new TspException(e);
        }
        return (SimpleTrigger) triggerBuilder.build();
    }
    
    /**
     * 
     * 功能说明:tsp子任务转换成具有cron表达式功能的触发器
     * 
     * @author ZHONGFUHUA
     * 
     * @throws TspException 
     *
     * @Date 2016年1月7日
     *
     */
    public static CronTrigger convert2CronTrigger(com.ffcs.crmd.tsp.server.jdbc.entity.JobDetail jobDetail,
        com.ffcs.crmd.tsp.server.jdbc.entity.Job job, boolean update) throws TspException {
        
        TriggerBuilder<Trigger> triggerBuilder = TriggerBuilder.newTrigger();
        if (StringUtils.isBlank(jobDetail.getName()) && StringUtils.isBlank(job.getName())) {
            throw new TspException("job detail name and job name can't be null");
        }
        
        if (StringUtils.isBlank(job.getCronExpression())) {
            throw new TspException("job detail cron expression can't be null");
        }
        
        if (jobDetail.getStartTime() == null) {
            if(update){
                Calendar calendar = Calendar.getInstance();
                calendar.add(Calendar.SECOND, 60);
                triggerBuilder.startAt(calendar.getTime());
            }else{
                triggerBuilder.startNow();
            }
        } else {
            Calendar calendar = Calendar.getInstance();
            calendar.add(Calendar.SECOND, 60);
            if(jobDetail.getStartTime().getTime() > calendar.getTime().getTime()){
                triggerBuilder.startAt(jobDetail.getStartTime());
            }else{
                triggerBuilder.startAt(calendar.getTime());
            }
        }
        
        try {
            CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronScheduleNonvalidatedExpression(job.getCronExpression());
            switch (job.getMisfireInstruction()) {
                case -1:
                    cronScheduleBuilder.withMisfireHandlingInstructionIgnoreMisfires();
                    break;
                case 1:
                    cronScheduleBuilder.withMisfireHandlingInstructionFireAndProceed();
                    break;
                case 2:
                    cronScheduleBuilder.withMisfireHandlingInstructionDoNothing();
                    break;
                default:
                    break;
            }
            cronScheduleBuilder.inTimeZone(TimeZone.getTimeZone("GMT+8:00"));
            triggerBuilder.withIdentity(MixAll.TSP_TRIGGER_PREFIX + jobDetail.getName(), MixAll.TSP_TRIGGER_PREFIX + job.getName());
            triggerBuilder.withSchedule(cronScheduleBuilder);
        } catch (Exception e) {
            throw new TspException(e);
        }
        
        return (CronTrigger) triggerBuilder.build();
    }
    
    /**
     * 
     * 功能说明:quartz子任务转换成tsp子任务
     * 
     * @param jobDetail
     * @param trigger
     * @return
     */
    public static TspJobInstance convert2TspJobDetail(JobDetail jobDetail, SimpleTrigger trigger) {
        TspJobInstance tspJobDetail = new TspJobInstance();
        tspJobDetail.setName(jobDetail.getKey().getName());
        tspJobDetail.setJobName(jobDetail.getKey().getGroup());
        tspJobDetail.setDescription(jobDetail.getDescription());
        tspJobDetail.setStartTime(trigger.getStartTime());
        tspJobDetail.setEndTime(trigger.getEndTime());
        return tspJobDetail;
    }
    
    /**
     * 
     * 功能说明:quartz子任务转换成tsp子任务
     * 
     * @param jobDetail
     * @param trigger
     * @return 
     */
    public static TspJobInstance convert2TspJobDetail(JobDetail jobDetail, CronTrigger trigger) {
        TspJobInstance tspJobDetail = new TspJobInstance();
        tspJobDetail.setName(jobDetail.getKey().getName());
        tspJobDetail.setJobName(jobDetail.getKey().getGroup());
        tspJobDetail.setDescription(jobDetail.getDescription());
        tspJobDetail.setStartTime(trigger.getStartTime());
        tspJobDetail.setEndTime(trigger.getEndTime());
        return tspJobDetail;
    }
    
    /**
     * 
     * 功能说明:quartz任务参数对象转化成tsp的任务参数对象
     * 
     * @param jobDataMap
     * @return
     */
    @SuppressWarnings("deprecation")
    public static TspJobDataMap convert2TspJobDataMap(JobDataMap jobDataMap) {
        TspJobDataMap tspJobDataMap = new TspJobDataMap(jobDataMap);
        if(StringUtils.isNoneBlank(jobDataMap.getString(TspAppConstant.TSP_PARAM_SLICES_GROUP))){
            tspJobDataMap.put(TspAppConstant.TSP_PARAM_SLICE_GROUP_NAME, jobDataMap.getString(TspAppConstant.TSP_PARAM_SLICES_GROUP));
        }
        
        if(StringUtils.isNoneBlank(jobDataMap.getString(TspAppConstant.TSP_PARAM_SLICES))){
            tspJobDataMap.put(TspAppConstant.TSP_PARAM_SLICE_GROUP, jobDataMap.getString(TspAppConstant.TSP_PARAM_SLICES));
        }
        return tspJobDataMap;
    }
    
    /**
     * 
     * 功能说明:tsp的任务参数对象转化成quartz任务参数对象
     * 
     * @param tspJobDataMap
     * @return
     */
    public static JobDataMap convert2JobDataMap(TspJobDataMap tspJobDataMap) {
        return new JobDataMap(tspJobDataMap.getMap());
    }
    
}
